package com.pdx.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.pdx.config.RedisService;
import com.pdx.constant.Constant;
import com.pdx.entity.SysDept;
import com.pdx.entity.SysRole;
import com.pdx.entity.SysUser;
import com.pdx.entity.vo.*;
import com.pdx.exception.BusinessException;
import com.pdx.exception.code.BaseResponseCode;
import com.pdx.mapper.SysDeptMapper;
import com.pdx.mapper.SysUserMapper;
import com.pdx.service.*;
import com.pdx.utils.JwtTokenUtil;
import com.pdx.utils.PasswordUtils;
import com.pdx.utils.TokenSetting;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author PDX
 * @website https://blog.csdn.net/Gaowumao
 * @Date 2022-05-01 00:14
 * @Description
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private TokenSetting tokenSetting;
    @Autowired
    private SysDeptMapper sysDeptMapper;

    /**
     * 用户登录
     * @param vo
     * @return
     */
    @Override
    public RespBody login(LoginVo vo) {
        String code = (String) redisService.get("captcha");
        //判断验证码是否过期
        if (!redisService.hasKey("captcha")){
            throw new BusinessException(BaseResponseCode.KEY_ALREADY_EXPIRED);
        }

        //忽略字符大小写校验验证码是否正确
        if (!vo.getCaptcha().equalsIgnoreCase(code)){
            throw new BusinessException(BaseResponseCode.CAPTCHA_ERROR);
        }

        //判断用户是否存在
        SysUser user = userMapper.getUserByName(vo.getUsername());
        if (user == null){
            throw new BusinessException(BaseResponseCode.ACCOUNT_ERROR);
        }
        //判断用户状态
        if (user.getStatus() == 2){
            throw new BusinessException(BaseResponseCode.ACCOUNT_LOCKED);
        }
        //校验密码
        if (!PasswordUtils.matches(user.getSalt(),vo.getPassword(),user.getPassword())){
            throw new BusinessException(BaseResponseCode.ACCOUNT_PASSWORD_ERROR);
        }
        RespBody body = new RespBody();
        body.setId(user.getId());
        body.setUsername(user.getUsername());
        Map<String,Object> claims = new HashMap<>();
        claims.put(Constant.ROLES_INFOS_KEY,getRoleByUserId(user.getId()));
        claims.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionByUserId(user.getId()));
        claims.put(Constant.JWT_USER_NAME,user.getUsername());
        String accessToken = JwtTokenUtil.getAccessToken(user.getId(), claims);
        body.setAccessToken(accessToken);
        return body;
    }

    @Override
    public void logout(String accessToken) {
        if (StringUtils.isEmpty(accessToken)){
            throw new BusinessException(BaseResponseCode.TOKEN_ERROR);
        }
        Subject subject = SecurityUtils.getSubject();
        if (subject!=null){
            subject.logout();
        }
        String userId = JwtTokenUtil.getUserId(accessToken);
        //加入黑名单
        redisService.set(Constant.JWT_ACCESS_TOKEN_BLACKLIST+accessToken,userId,JwtTokenUtil.getRemainingTime(accessToken), TimeUnit.MILLISECONDS);
    }

    /**
     * 条件分页查询数据
     * @param vo
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Map<String, Object> page(QueryVo vo, int pageNo, int pageSize) {
        PageHelper.startPage(pageNo,pageSize);
        List<SysUser> users = userMapper.selectAll(vo);
        for (SysUser user : users) {
            SysDept sysDept = sysDeptMapper.selectByPrimaryKey(user.getDeptId());
            if (sysDept != null){
                user.setDeptName(sysDept.getName());
            }
        }
        PageInfo<SysUser> pageInfo  = new PageInfo<>(users);
        long total = pageInfo.getTotal();
        List<SysUser> list = pageInfo.getList();
        Map<String,Object> map = new HashMap<>();
        map.put("users",list);
        map.put("total",total);
        return map;
    }

    @Override
    public void addUser(SysUser sysUser) {
        sysUser.setId(UUID.randomUUID().toString());
        String accessToken = (String) SecurityUtils.getSubject().getPrincipal();
        String userId = JwtTokenUtil.getUserId(accessToken);
        sysUser.setCreateId(userId);
        String salt = PasswordUtils.getSalt();
        sysUser.setSalt(salt);
        String encode = PasswordUtils.encode(sysUser.getPassword(), salt);
        sysUser.setPassword(encode);
        sysUser.setDeleted(1);
        sysUser.setStatus(2);
        sysUser.setCreateTime(new Date());
        int result = userMapper.insert(sysUser);
        if (result != 1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
    }

    /**
     * 修改用户信息
     * @param user
     * @param operateId
     */
    @Override
    public void updateUser(SysUser user, String operateId) {
        user.setUpdateId(operateId);
        user.setUpdateTime(new Date());
        if (StringUtils.isEmpty(user.getPassword())){
            user.setPassword(null);
        }else {
            String salt = user.getSalt();
            String encode = PasswordUtils.encode(user.getPassword(), salt);
            user.setPassword(encode);
        }
        int result = userMapper.updateByPrimaryKeySelective(user);
        if (result != 1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //用户锁定
        if (user.getStatus() == 2){
            redisService.set(Constant.ACCOUNT_LOCK_KEY+user.getId(),user.getId());
        }else {
            redisService.delete(Constant.DELETE_USER_KEY+user.getId());
        }

    }

    /**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */
    @Override
    public SysUser getUserInfoById(String id) {
        SysUser user = userMapper.selectUserInfoById(id);
        return user;
    }

    /**
     * 查询用户拥有的角色数据接口
     * @param userId
     * @return
     */
    @Override
    public UserOwnRoleRespVo getUserOwnRole(String userId) {
        UserOwnRoleRespVo userOwnRoleRespVo = new UserOwnRoleRespVo();
        List<String> list = userRoleService.getRoleIdsByUserId(userId);
        List<SysRole> roleList = roleService.selectAll();
        userOwnRoleRespVo.setOwnRoles(list);
        userOwnRoleRespVo.setAllRole(roleList);
        return userOwnRoleRespVo;
    }

    @Override
    public void setUserOwnRole(UserOwnRoleVo vo) {
        userRoleService.addUserRoleInfo(vo);
        /*
        * 标记用户
        * */
        redisService.set(Constant.JWT_REFRESH_KEY+vo.getUserId(),vo.getUserId(),tokenSetting.getAccessTokenExpireTime().toMillis(),TimeUnit.MILLISECONDS);
    }

    /**
     * 修改用户信息
     * @param vo
     * @param userId
     */
    @Override
    public void updateUserInfo(UserUpdateVo vo, String userId) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(vo,user);
        user.setUpdateTime(new Date());
        user.setUpdateId(userId);
        if (StringUtils.isEmpty(vo.getPassword())){
            user.setPassword(null);
        }else {
            String salt = PasswordUtils.getSalt();
            String encode = PasswordUtils.encode(vo.getPassword(), salt);
            user.setPassword(encode);
        }
        int i = userMapper.updateByPrimaryKeySelective(user);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        if (vo.getStatus() == 2){
            redisService.set(Constant.ACCOUNT_LOCK_KEY+vo.getId(),vo.getId());
        }else {
            redisService.delete(Constant.ACCOUNT_LOCK_KEY+vo.getId());
        }
    }

    @Override
    public void deleteUsers(List<String> list, String userId) {
        SysUser user = new SysUser();
        user.setUpdateId(userId);
        user.setUpdateTime(new Date());
        int i = userMapper.deletedUsers(user,list);
        if (i == 0){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        for (String id : list) {
            redisService.set(Constant.DELETE_USER_KEY+id,id,tokenSetting.getAccessTokenExpireTime().toMillis(),TimeUnit.MILLISECONDS);
        }
    }

    /**
     * 根据用户id获取用户权限
     * @param id
     * @return
     */
    private List<String> getPermissionByUserId(String id) {
        List<String> permissionByUserId = permissionService.getPermissionByUserId(id);
        return permissionByUserId;
    }
    /**
     * 根据用户Id查询角色信息
     * @param id
     * @return
     */
    private List<String> getRoleByUserId(String id) {
        List<String> namesByUserId = roleService.getNamesByUserId(id);
        return namesByUserId;
    }
}
